{
  stdenv,
  lib,
  buildEnv,
  buildRubyGem,
  ruby,
  gemConfig,
  makeBinaryWrapper,
}:

/*
  Example usage:
  nix-shell -E "(import <nixpkgs> {}).ruby.withPackages (pkgs: with pkgs; [ pry nokogiri ])"

  You can also use this for writing ruby scripts that run anywhere that has nix
  using a nix-shell shebang:
    #!/usr/bin/env nix-shell
    #!nix-shell -i ruby -p "ruby.withPackages (pkgs: with pkgs; [ pry nokogiri ])"

  Run the following in the nixpkgs root directory to update the ruby-packages.nix:
  ./maintainers/scripts/update-ruby-packages
*/

let
  functions = import ../bundled-common/functions.nix { inherit lib gemConfig; };

  buildGems =
    gemset:
    let
      realGemset = if builtins.isAttrs gemset then gemset else import gemset;
      builtGems = lib.mapAttrs (
        name: initialAttrs:
        let
          attrs = functions.applyGemConfigs (
            {
              inherit ruby;
              gemName = name;
            }
            // initialAttrs
          );
        in
        buildRubyGem (functions.composeGemAttrs ruby builtGems name attrs)
      ) realGemset;
    in
    builtGems;

  gems = buildGems (import ../../../top-level/ruby-packages.nix);

  withPackages =
    selector:
    let
      selected = selector gems;

      gemEnv = buildEnv {
        name = "ruby-gems";
        paths = selected;
        pathsToLink = [
          "/lib"
          "/bin"
          "/nix-support"
        ];
      };

      wrappedRuby = stdenv.mkDerivation {
        name = "wrapped-${ruby.name}";
        nativeBuildInputs = [ makeBinaryWrapper ];
        buildCommand = ''
          mkdir -p $out/bin
          for i in ${ruby}/bin/*; do
            makeWrapper "$i" $out/bin/$(basename "$i") --set GEM_PATH ${gemEnv}/${ruby.gemPath}
          done
        '';
      };

    in
    stdenv.mkDerivation {
      name = "${ruby.name}-with-packages";
      nativeBuildInputs = [ makeBinaryWrapper ];
      buildInputs = [
        selected
        ruby
      ];

      dontUnpack = true;

      installPhase = ''
        for i in ${ruby}/bin/* ${gemEnv}/bin/*; do
          rm -f $out/bin/$(basename "$i")
          makeWrapper "$i" $out/bin/$(basename "$i") --set GEM_PATH ${gemEnv}/${ruby.gemPath}
        done

        ln -s ${ruby}/nix-support $out/nix-support
      '';

      passthru = {
        inherit wrappedRuby;
        gems = selected;
      };

      meta.mainProgram = "ruby";
    };

in
{
  inherit withPackages gems buildGems;
}
